/*
 * @(#)TestSetRunner.java
 *
 *
 *
 * ver 1.0 Aug 30, 2007 ggranum
 */
package org.testfire.agent.runner;

import com.sun.tools.javac.Main;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.testfire.agent.AgentProperties;
import org.testfire.model.TestResultType;
import org.testfire.model.TestType;
import org.testfire.model.TestsetResultType;
import org.testfire.model.TestsetType;

public class TestSetRunner
{

    public static final String[] classPaths = {
        "/xml-apis.jar",
        "/xercesSamples.jar",
        "/xercesImpl.jar",
        "/junit-4.4.jar",
        "/watij.jar"
    };

    public static final String classpath;

    static
    {
        String c = "";
        for ( String s : classPaths )
        {
            c += AgentProperties.getInstance().getJarsDirectory() + s + ";";
        }
        classpath = c;
    }

    public static TestsetType run( TestsetType testset )
    {

        AgentProperties agentProps = AgentProperties.getInstance();
        Result result;
        try
        {

            String classPackage = testset.getClassPackage();
            File classDir = new File( agentProps.getClassesDirectory(), classPackage.replace( '.', '/' ) );
            File javaFileDir = new File( agentProps.getTestSrcDirectory(), classPackage.replace( '.', '/' ) );
            if ( !classDir.exists() )
            {
                classDir.mkdirs();
            }
            if ( !javaFileDir.exists() )
            {
                javaFileDir.mkdirs();
            }
            String testsetName = testset.getName();

            File classFile = new File( classDir, testsetName + ".class" );
            File javaFile = new File( javaFileDir, testsetName + ".java" );
            if ( classFile.exists() )
            {
                classFile.delete();
            }
            if ( javaFile.exists() )
            {
                javaFile.delete();
            }

            FileWriter out = new FileWriter( javaFile, false );
            out.write( String.valueOf( testset.translate( testset ) ) );
            out.close();

            String[] args = {
                "-classpath", classpath,
                "-d", agentProps.getClassesDirectory().getCanonicalPath(),
                javaFile.getCanonicalPath()};

            int errorCode = Main.compile( args );
            if ( errorCode != 0 )
            {
                throw new Exception( "Could not compile passed testset!" );
            }

            URLClassLoader loader = new URLClassLoader( new URL[]{agentProps.getClassesDirectory().toURL()},
                TestSetRunner.class.getClassLoader() );

            Class c = loader.loadClass( classPackage + "." + testsetName );

            List<TestType> tests = testset.getTests();
            final Map<String, TestResultType> testMap = new HashMap<String, TestResultType>( );
            final Date runDate = new Date();
            TestsetResultType testsetResult = new TestsetResultType( testset );
            testsetResult.setRunDate( runDate );
            for(TestType test : tests){
                TestResultType testResult = new TestResultType( test );
                testResult.setRunDate( runDate );
                testMap.put( test.getName(), testResult );
            }

//            long rundId = testset.getUserName().hashCode()

            JUnitCore core= new JUnitCore();
            core.addListener( new RunListener(){
                long timerStart = 0;
                public void testFinished( Description description ) throws Exception
                {
                    TestResultType result = common(description);
                    if(result != null)
                    {
                        result.setResult( TestResultType.PASSED  );
                        System.out.println( "Finished: " + description + " in " + result.getRunTime() + " millis"  );
                    }
                }

                public void testStarted( Description description ) throws Exception
                {
                    this.timerStart = System.currentTimeMillis();
                }

                public void testIgnored( Description description ) throws Exception
                {
                    TestResultType result = common(description);
                    result.setResult( TestResultType.IGNORED  );

                }

                public TestResultType common(Description description){
                    long timerEnd = System.currentTimeMillis();
                    int delta = timerStart == 0 ? 0 : (int)(timerEnd - timerStart);
                    String testName = description.getDisplayName();
                    testName = testName.substring( 0, testName.indexOf( "(")) ;
                    TestResultType result = testMap.get( testName );
                    if(result != null)
                    {
                        result.setDescription( description.toString() );
                        result.setRunTime( delta );
                    }
                    return result;
                }
            });

            result = core.run(c);
            testsetResult.setTimeElapsed( (int)result.getRunTime() );
            testsetResult.setFailureCount(result.getFailureCount());
            testsetResult.setIgnoreCount(result.getIgnoreCount());
            testsetResult.setRunCount(result.getRunCount());
            testsetResult.setWasSuccessful( result.wasSuccessful() );
            List<Failure> failures = result.getFailures();
            if ( failures == null || failures.size() == 0 )
            {
                System.out.println( "\n\n" + testsetName + " Passed" );
            }
            else
            {
                for ( Failure f : failures )
                {
                    Description d = f.getDescription();
                    String testName = d.getDisplayName();
                    testName = testName.substring( 0, testName.indexOf( "(")) ;
                    TestResultType testResult = testMap.get( testName );
                    if(testResult != null)
                    {
                        testResult.setResult( TestResultType.FAILED );
                        testResult.setFailure( f.getMessage(), f.getTrace(), f.getTestHeader());
                    }
                }
            }
        }
        catch ( Error e )
        {
            e.printStackTrace();
        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
       
        return testset;

    }

   
}

// eof: TestSetRunner.java